#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
//#include <vld.h>
#include "Game.h"
#include <stdlib.h>
#include "Definitions.h"

//*********************************************************************
// Preprocessor Constants
#define WINDOW_CLASS_NAME	((const wchar_t*)L"Fantasy Fall")			// window class name
#define WINDOW_TITLE		((const wchar_t*)L"Fantasy Fall")			// window title
#define WINDOW_WIDTH		((int)800)									// window width
#define WINDOW_HEIGHT		((int)600)									// window height

/*********************************************************************/
// Function Declarations
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
bool IsAlreadyRunning();
HWND MakeWindow(HINSTANCE hInstance);
LRESULT CALLBACK WindowProc	(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

/*********************************************************************/
// WinMain
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	_CrtSetBreakAlloc(-1);

	if( IsAlreadyRunning() == true )
		return -1;
    
	HWND hWnd = MakeWindow(hInstance);
	if(hWnd == 0)
	{
		MessageBoxW(HWND_DESKTOP, L"ERROR: Failed to create the Main Window.", WINDOW_TITLE, MB_OK | MB_ICONERROR);
		return -2;
	}

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow( hWnd );

	
	/****************************************************************/
	// Initialize game
	if(GAME->Initialize( WINDOW_WIDTH, WINDOW_HEIGHT ) == false)
		return -3;

	MSG msg = { };
	while(true)
	{
		if(PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE ) == TRUE)
		{ 
			/*******************************************************/
			// Quit Game
			if(msg.message == WM_QUIT)
				break;
		
			DispatchMessageW(&msg);
		}
		else
		{
			/*******************************************************/
			// Run game
			int result = GAME->Update();
			if( result != 0 )
				PostQuitMessage( result );
		}
	}
	
	/***************************************************************/
	// Terminate game
	
	GAME->Terminate();
	Game::DeleteInstance();

	UnregisterClassW(WINDOW_CLASS_NAME, hInstance);
	
	return (int)(msg.wParam);
}

bool IsAlreadyRunning(void)
{
	HWND hOtherWnd = FindWindowW(WINDOW_CLASS_NAME, WINDOW_TITLE);
	if(hOtherWnd != 0)
	{
		if( IsIconic(hOtherWnd) == TRUE)
			ShowWindow(hOtherWnd, SW_RESTORE);

		SetForegroundWindow(hOtherWnd);
		return true;
	}

	return false;
}

HWND MakeWindow(HINSTANCE hInstance)
{
	WNDCLASSEXW	winClassEx;

	winClassEx.cbSize			= sizeof(winClassEx);
	winClassEx.style			= CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
	winClassEx.lpfnWndProc		= WindowProc;
	winClassEx.cbClsExtra		= 0;
	winClassEx.cbWndExtra		= 0;
	winClassEx.hInstance		= hInstance;
	winClassEx.hIcon			= LoadIconW( NULL, (LPWSTR)IDI_APPLICATION );
	winClassEx.hIconSm			= LoadIconW( NULL, (LPWSTR)IDI_APPLICATION );
	winClassEx.hCursor			= LoadCursorW( NULL, (LPWSTR)IDC_ARROW );
	winClassEx.hbrBackground	= (HBRUSH)(1+COLOR_WINDOW);
	winClassEx.lpszMenuName		= NULL; 
	winClassEx.lpszClassName	= WINDOW_CLASS_NAME;

	ATOM atomClass = RegisterClassExW( &winClassEx );
	if( atomClass == 0 )
		return 0;

	DWORD dwWindowStyleFlags = WS_VISIBLE | WS_POPUP | WS_SYSMENU | WS_MINIMIZEBOX;

	RECT rWindow;
	rWindow.left	= 0;
	rWindow.top		= 0;
	rWindow.right	= WINDOW_WIDTH;
	rWindow.bottom	= WINDOW_HEIGHT;

	AdjustWindowRectEx(&rWindow, dwWindowStyleFlags, FALSE, WS_EX_APPWINDOW);
	
	int nWindowWidth	= rWindow.right  - rWindow.left;
	int nWindowHeight	= rWindow.bottom - rWindow.top;

	HWND hWnd = CreateWindowExW(
					WS_EX_APPWINDOW,										// extended style flags
					WINDOW_CLASS_NAME,										// window class Name
					WINDOW_TITLE,											// title
					dwWindowStyleFlags,										// window style flags
					(GetSystemMetrics(SM_CXSCREEN) - nWindowWidth)/2,		// position (x, y)
					(GetSystemMetrics(SM_CYSCREEN) - nWindowHeight)/2,		//	- centered on the desktop
					nWindowWidth,											// width
					nWindowHeight,											// height
					HWND_DESKTOP,											// parent window handle
					NULL,													// menu handle
					hInstance,												// application instance
					NULL													// creation parameters
				);

	if(hWnd == 0)
		UnregisterClassW(WINDOW_CLASS_NAME, hInstance);

	return hWnd;
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
	case WM_CREATE:
		break;
	case WM_CLOSE:
		DestroyWindow(hWnd);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	case WM_SYSKEYUP:
	case WM_SYSCHAR:
		break;
	case WM_ACTIVATE:
		if( LOWORD(wParam) != WA_INACTIVE )
		{
		}
		else
		{
		}
		break;
	case WM_PAINT:
		ValidateRect(hWnd, nullptr);
		break;
	default:
		return DefWindowProcW(hWnd, msg, wParam, lParam);
	}
	return 0;
}
